<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8"/>
    <title>智能校园助手 - 云南财经大学</title>
    <style>
        *{box-sizing:border-box;margin:0;padding:0}
        html,body{height:100%;font-family:"Microsoft YaHei",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif;background:#f8f9fa;color:#333}

        /* 顶部导航栏 - 学院风格 */
        .header{background:linear-gradient(135deg, #003366 0%, #004d99 100%);color:white;padding:15px 30px;display:flex;align-items:center;justify-content:space-between;box-shadow:0 2px 10px rgba(0,0,0,0.1)}
        .header .logo{display:flex;align-items:center;font-size:24px;font-weight:bold}
        .header .logo img{height:40px;margin-right:15px}
        .header .nav{display:flex;gap:30px;font-size:14px}
        .header .nav a{color:white;text-decoration:none;transition:opacity 0.3s}
        .header .nav a:hover{opacity:0.8}

        /* 主体容器 */
        .main-container{display:flex;height:calc(100% - 70px);position:relative}

        /* 左侧历史记录 - 学院风格 */
        #history{width:280px;background:#fff;border-right:1px solid #e0e0e0;display:flex;flex-direction:column;transition:width .3s}
        #history.collapsed{width:50px}
        #historyHeader{background:#f1f3f5;padding:20px;border-bottom:1px solid #e0e0e0;display:flex;align-items:center;justify-content:space-between}
        #historyHeader h3{font-size:16px;color:#003366;font-weight:600}
        #toggleHistory{background:none;border:none;font-size:18px;cursor:pointer;color:#003366}
        #historyList{flex:1;overflow-y:auto;padding:15px}
        .history-item{margin-bottom:12px;padding:12px;background:#f8f9fa;border-radius:6px;cursor:pointer;transition:all 0.3s;border-left:3px solid transparent}
        .history-item:hover{background:#e9ecef;transform:translateX(2px)}
        .history-item.active{background:#e3f2fd;border-left:3px solid #003366}
        .history-item .title{font-size:14px;color:#003366;font-weight:500;margin-bottom:4px}
        .history-item .time{font-size:12px;color:#6c757d}

        /* 中间对话区 - 学院风格 */
        #chat{flex:1;display:flex;flex-direction:column;background:#fff;margin:20px;border-radius:12px;box-shadow:0 4px 20px rgba(0,0,0,0.08);overflow:hidden;position:relative}
        #chatHeader{background:linear-gradient(135deg, #003366 0%, #004d99 100%);color:white;padding:20px;font-size:18px;font-weight:600;display:flex;align-items:center;gap:15px}
        #chatHeader .avatar{width:40px;height:40px;border-radius:50%;background:white;display:flex;align-items:center;justify-content:center;font-size:20px}
        #chatBody{flex:1;display:flex;flex-direction:column;min-height:0}
        #bubbleBox{flex:1;overflow-y:auto;padding:25px;background:#fafbfc}
        .bubble{margin:15px 0;display:flex;align-items:flex-start}
        .bubble.user{justify-content:flex-end}
        .bubble.assistant{justify-content:flex-start}
        .bubble .txt{max-width:65%;padding:14px 18px;border-radius:18px;font-size:15px;line-height:1.6;white-space:pre-wrap;word-wrap:break-word;box-shadow:0 2px 8px rgba(0,0,0,0.05)}
        .bubble.user .txt{background:#003366;color:white;border-bottom-right-radius:4px}
        .bubble.assistant .txt{background:#f1f3f5;color:#212529;border-bottom-left-radius:4px;border:1px solid #e9ecef}

        /* 流式文本效果 */
        .typing-cursor {
            display: inline-block;
            width: 8px;
            height: 16px;
            background: #003366;
            margin-left: 2px;
            animation: blink 1s infinite;
            vertical-align: middle;
        }
        @keyframes blink {
            0%, 100% { opacity: 1; }
            50% { opacity: 0; }
        }

        /* 控制区域 - 学院风格 */
        #ctrlArea{background:#fff;border-top:1px solid #e9ecef;padding:20px;display:flex;align-items:center;gap:15px;position:relative;z-index:5}
        #inputArea{flex:1;display:flex;gap:12px}
        #textInput{flex:1;padding:14px 20px;border:1px solid #ced4da;border-radius:25px;font-size:15px;outline:none;transition:all 0.3s;background:#f8f9fa}
        #textInput:focus{border-color:#003366;background:#fff;box-shadow:0 0 0 3px rgba(0,51,102,0.1)}
        #sendBtn{height:48px;width:90px;font-size:15px;border:none;border-radius:24px;background:#003366;color:#fff;cursor:pointer;transition:all 0.3s;font-weight:500}
        #sendBtn:hover{background:#002244;transform:translateY(-1px);box-shadow:0 4px 12px rgba(0,51,102,0.3)}
        #sendBtn:disabled{background:#6c757d;cursor:not-allowed;transform:none;box-shadow:none}

        #voiceArea{display:flex;align-items:center;gap:12px}
        #recBtn{height:48px;width:110px;font-size:15px;border:none;border-radius:24px;background:#28a745;color:#fff;cursor:pointer;transition:all 0.3s;font-weight:500}
        #recBtn:active{background:#218838;transform:scale(0.98)}
        #recBtn.recording{background:#dc3545;animation:pulse 1.5s infinite}
        @keyframes pulse {
            0% { transform: scale(1); }
            50% { transform: scale(1.05); }
            100% { transform: scale(1); }
        }

        #stopBtn{height:48px;width:110px;font-size:15px;border:none;border-radius:24px;background:#ff4d4f;color:#fff;cursor:pointer;font-weight:500;transition:all 0.3s}
        #stopBtn:disabled{background:#6c757d;cursor:not-allowed}
        #stopBtn.reading{background:#ff7875}
        #newSessionBtn{height:48px;width:130px;font-size:15px;border:1px solid #003366;border-radius:24px;background:#fff;color:#003366;cursor:pointer;font-weight:500;transition:all 0.3s}
        #newSessionBtn:hover{background:#003366;color:#fff}

        /* 输入模式切换 - 学院风格 */
        #inputMode{display:flex;background:#f1f3f5;border-radius:25px;padding:4px;margin-bottom:15px;width:fit-content}
        .modeBtn{padding:10px 20px;border:none;background:transparent;border-radius:20px;cursor:pointer;font-size:14px;transition:all 0.3s;font-weight:500}
        .modeBtn.active{background:#003366;color:white}

        /* 右侧资料展示 - 学院风格 */
        #material{width:320px;background:#fff;border-left:1px solid #e0e0e0;display:flex;flex-direction:column;margin:20px 20px 20px 0;border-radius:12px;box-shadow:0 4px 20px rgba(0,0,0,0.08);overflow:hidden}
        #material h3{background:#f1f3f5;padding:20px;font-size:16px;font-weight:600;border-bottom:1px solid #e9ecef;display:flex;justify-content:space-between;align-items:center;color:#003366}
        #materialContent{flex:1;overflow-y:auto;padding:20px;font-size:14px;color:#495057;line-height:1.7}

        /* 图片展示样式 */
        .image-container {margin-bottom:20px;border:1px solid #e9ecef;border-radius:8px;padding:15px;background:#fff;box-shadow:0 2px 8px rgba(0,0,0,0.05)}
        .image-title{font-weight:600;margin-bottom:8px;color:#003366;font-size:15px}
        .image-description{font-size:13px;color:#6c757d;margin-bottom:10px}
        .image-preview{max-width:100%;max-height:200px;border-radius:6px;display:block;margin:0 auto;cursor:pointer;transition:transform 0.2s;border:1px solid #e9ecef}
        .image-preview:hover{transform:scale(1.02)}
        .no-images{text-align:center;color:#6c757d;font-style:italic;padding:30px;background:#f8f9fa;border-radius:8px}

        /* 搜索信息样式 */
        .search-info{background:#e3f2fd;padding:12px;border-radius:6px;margin-bottom:12px;font-size:13px;border-left:3px solid #003366}
        .intent-badge{display:inline-block;background:#003366;color:white;padding:3px 8px;border-radius:12px;font-size:11px;margin-right:6px;font-weight:500}
        .session-badge{display:inline-block;background:#28a745;color:white;padding:3px 8px;border-radius:12px;font-size:11px;font-weight:500}

        /* 会话信息样式 */
        .session-info{background:#f3e5f5;padding:12px;border-radius:6px;margin-bottom:12px;font-size:13px;border-left:3px solid #7b1fa2}

        /* 状态提示 - 学院风格 */
        #status{position:fixed;bottom:90px;left:50%;transform:translateX(-50%);background:rgba(0,51,102,0.9);color:white;padding:10px 20px;border-radius:25px;font-size:13px;z-index:1000;display:none;box-shadow:0 4px 12px rgba(0,0,0,0.2)}

        /* 视频动画覆盖层 - 修改为只覆盖中间区域 */
        #videoOverlay{
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: calc(100% - 140px); /* 减去输入区域高度 */
            background: rgba(0, 0, 0, 0.85);
            z-index: 10;
            display: none;
            overflow: hidden;
            border-radius: 12px;
        }
        #videoContainer{
            position: relative;
            width: 100%;
            height: 100%;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        #videoPlayer{
            width: 90%;
            height: 90%;
            object-fit: contain;
            border-radius: 12px;
        }
        #shrinkVideoBtn{
            position: absolute;
            top: 20px;
            right: 20px;
            background: rgba(255, 255, 255, 0.2);
            color: white;
            border: none;
            border-radius: 50%;
            width: 44px;
            height: 44px;
            font-size: 20px;
            cursor: pointer;
            z-index: 20;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: all 0.3s;
        }
        #shrinkVideoBtn:hover{
            background: rgba(255, 255, 255, 0.3);
            transform: scale(1.1);
        }

        /* 小窗口视频样式 - 修改为放在中间栏右下角 */
        #miniVideo{
            position: absolute;
            bottom: 100px; /* 放在输入区域上方 */
            right: 25px;
            width: 220px;
            height: 165px;
            background: rgba(0, 0, 0, 0.8);
            border-radius: 12px;
            overflow: hidden;
            z-index: 20;
            display: none;
            box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
        }
        #miniVideoPlayer{
            width: 100%;
            height: 100%;
            object-fit: cover;
        }
        .mini-video-controls{
            position: absolute;
            top: 8px;
            right: 8px;
            display: flex;
            gap: 6px;
        }
        .mini-control-btn{
            background: rgba(255, 255, 255, 0.2);
            color: white;
            border: none;
            border-radius: 50%;
            width: 32px;
            height: 32px;
            font-size: 16px;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: all 0.3s;
        }
        .mini-control-btn:hover{
            background: rgba(255, 255, 255, 0.3);
            transform: scale(1.1);
        }

        /* 预加载视频元素（隐藏） */
        #preloadVideoContainer{display:none}

        /* 欢迎提示 - 学院风格 */
        .welcome-tip{background:linear-gradient(135deg, #e3f2fd 0%, #f1f8e9 100%);border:1px solid #bbdefb;border-radius:12px;padding:20px;margin-bottom:20px;text-align:center}
        .welcome-tip h4{color:#003366;margin-bottom:10px;font-size:16px}
        .welcome-tip p{color:#546e7a;font-size:14px;margin:0}

        /* 响应式设计 */
        @media (max-width: 1200px) {
            #material{width:280px}
            #history{width:250px}
        }
        @media (max-width: 768px) {
            .header{padding:10px 15px}
            .header .nav{display:none}
            .main-container{flex-direction:column}
            #history{width:100%;height:200px;border-right:none;border-bottom:1px solid #e0e0e0}
            #material{width:100%;height:200px;border-left:none;border-top:1px solid #e0e0e0;margin:0}
            #chat{margin:10px}
            #miniVideo{
                width: 180px;
                height: 135px;
                bottom: 90px;
                right: 15px;
            }
        }
    </style>
</head>
<body>

<!-- 顶部导航栏 -->
<header class="header">
    <div class="logo">
        <img src="logo/logo.jpg" alt="校徽">
        <span>云南财经大学信息学院 · 智能校园助手</span>
    </div>
    <nav class="nav">
        <a href="#home">首页</a>
        <a href="#about">关于我们</a>
        <a href="#services">服务指南</a>
        <a href="#contact">联系方式</a>
    </nav>
</header>

<!-- 主体容器 -->
<div class="main-container">

    <!-- 左侧历史记录 -->
    <aside id="history">
        <div id="historyHeader">
            <h3>历史对话</h3>
            <button id="toggleHistory" onclick="toggleHistory()" title="折叠/展开">☰</button>
        </div>
        <div id="historyList"></div>
    </aside>

    <!-- 中间对话区 -->
    <main id="chat">
        <div id="chatHeader">
            <div class="avatar">🎓</div>
            <div>
                <div>智能校园助手</div>
                <small style="font-size:12px;opacity:0.8">基于先进AI技术，为您提供校园服务</small>
            </div>
        </div>
        <div id="chatBody">
            <div id="bubbleBox">
                <div class="welcome-tip">
                    <h4> 欢迎来到云南财经大学信息学院智能校园助手</h4>
                    <p>我是您的专属校园助手，可以帮您查询校园信息、导航位置、了解学校历史等。<br>
                        请选择文字输入或语音输入开始对话。</p>
                </div>
            </div>

            <!-- 输入模式切换 -->
            <div id="inputMode">
                <button class="modeBtn active" onclick="setInputMode('text')">📝 文字输入</button>
                <button class="modeBtn" onclick="setInputMode('voice')">🎤 语音输入</button>
            </div>

            <!-- 控制区域 -->
            <div id="ctrlArea">
                <button id="newSessionBtn" onclick="startNewSession()">
                    <span style="margin-right:5px">➕</span>新会话
                </button>

                <!-- 文字输入区域 -->
                <div id="inputArea">
                    <input type="text" id="textInput" placeholder="请输入您的问题，例如：图书馆在哪里？" onkeypress="handleKeyPress(event)">
                    <button id="sendBtn" onclick="sendTextMessage()">发送</button>
                </div>

                <!-- 语音输入区域 -->
                <div id="voiceArea" style="display:none">
                    <button id="recBtn" onmousedown="startRec()" onmouseup="stopRec()" ontouchstart="startRec()" ontouchend="stopRec()">
                        <span style="margin-right:5px">🎤</span>按住说话
                    </button>
                    <button id="stopBtn" onclick="stopSpeak()" disabled>
                        <span style="margin-right:5px">⏹</span>停止对话
                    </button>
                </div>
            </div>
        </div>

        <!-- 视频动画覆盖层 -->
        <div id="videoOverlay">
            <div id="videoContainer">
                <video id="videoPlayer" loop muted></video>
                <button id="shrinkVideoBtn" onclick="shrinkVideo()">﹣</button>
            </div>
        </div>

        <!-- 小窗口视频 -->
        <div id="miniVideo">
            <video id="miniVideoPlayer" loop muted></video>
            <div class="mini-video-controls">
                <button class="mini-control-btn" onclick="expandVideo()">➕</button>
            </div>
        </div>

        <!-- 预加载视频容器 -->
        <div id="preloadVideoContainer">
            <video id="preloadVideo" preload="auto"></video>
        </div>
    </main>

    <!-- 右侧资料展示 -->
    <aside id="material">
        <h3>
            <span>相关资料</span>
            <span id="sessionIndicator" class="session-badge" style="display:none">会话中</span>
        </h3>
        <div id="materialContent" class="no-images">
            <div style="text-align:center;padding:20px;">
                <div style="font-size:48px;margin-bottom:10px">📚</div>
                <p>对话开始后，相关校园信息将在这里展示</p>
            </div>
        </div>
    </aside>

</div>

<!-- 状态提示 -->
<div id="status"></div>

<script>
    /* ---------- 全局变量 ---------- */
    let currentStreamController = null;
    let currentAssistantBubble = null;
    let accumulatedText = '';
    let currentSessionId = localStorage.getItem('currentSessionId') || generateSessionId();
    let currentInputMode = 'text'; // 默认文字输入模式
    let xfTtsSocket = null;
    let audioContext = null;
    let audioQueue = [];
    let isPlaying = false;
    let isVideoPlaying = false; // 标记视频是否正在播放
    let currentVideoType = null; // 'speaking' 或 'idle'
    let sessionHistory = {}; // 存储每个会话的第一条消息
    let videoPreloadStatus = { // 视频预加载状态
        'speaking': false,
        'idle': false
    };

    // 讯飞TTS配置
    const XF_TTS_CONFIG = {
        APPID: '70775e36',
        API_SECRET: 'OWJhNmM1YzY0NzQ5NzNkZGJiYmVmMGFi',
        API_KEY: 'bc40d85e9fa55c7d61da2fb1dc11fdc6',
        HOST: 'tts-api.xfyun.cn',
        PATH: '/v2/tts'
    };

    /* ---------- 视频预加载 ---------- */
    function preloadVideo(videoType) {
        // 如果已经预加载，则跳过
        if (videoPreloadStatus[videoType]) return;

        const preloadVideo = document.getElementById('preloadVideo');
        let videoSrc = '';

        if (videoType === 'speaking') {
            videoSrc = '/video/mv.mp4';
        } else if (videoType === 'idle') {
            videoSrc = '/video/mv1.mp4';
        }

        // 创建新的视频元素用于预加载
        const tempVideo = document.createElement('video');
        tempVideo.src = videoSrc;
        tempVideo.preload = 'auto';

        tempVideo.addEventListener('loadeddata', () => {
            console.log(`预加载完成: ${videoType}`);
            videoPreloadStatus[videoType] = true;
        });

        tempVideo.addEventListener('error', (e) => {
            console.error(`预加载失败: ${videoType}`, e);
        });

        // 开始加载
        tempVideo.load();
    }

    /* ---------- 视频动画控制 ---------- */
    function showVideoOverlay(videoType) {
        const videoOverlay = document.getElementById('videoOverlay');
        const videoPlayer = document.getElementById('videoPlayer');
        const miniVideo = document.getElementById('miniVideo');

        // 如果小窗口正在显示，则隐藏它
        if (miniVideo.style.display === 'block') {
            miniVideo.style.display = 'none';
        }

        // 根据类型设置视频源
        let videoSrc = '';
        if (videoType === 'speaking') {
            videoSrc = '/video/mv.mp4';
            currentVideoType = 'speaking';
        } else if (videoType === 'idle') {
            videoSrc = '/video/mv1.mp4';
            currentVideoType = 'idle';
        }

        // 设置视频源
        videoPlayer.src = videoSrc;
        videoPlayer.loop = true;
        videoPlayer.muted = true; // 静音，因为我们只需要动画

        // 播放视频
        videoPlayer.play().catch(e => console.error('视频播放失败:', e));

        // 显示覆盖层
        videoOverlay.style.display = 'block';
        isVideoPlaying = true;

        // 预加载其他视频
        if (videoType === 'speaking') {
            preloadVideo('idle');
        } else {
            preloadVideo('speaking');
        }
    }

    function hideVideoOverlay() {
        const videoOverlay = document.getElementById('videoOverlay');
        const videoPlayer = document.getElementById('videoPlayer');

        // 停止视频播放
        videoPlayer.pause();
        videoPlayer.src = '';

        // 隐藏覆盖层
        videoOverlay.style.display = 'none';
        isVideoPlaying = false;
        currentVideoType = null;
    }

    function shrinkVideo() {
        const videoOverlay = document.getElementById('videoOverlay');
        const videoPlayer = document.getElementById('videoPlayer');
        const miniVideo = document.getElementById('miniVideo');
        const miniVideoPlayer = document.getElementById('miniVideoPlayer');

        // 将当前视频源设置给小窗口
        miniVideoPlayer.src = videoPlayer.src;
        miniVideoPlayer.loop = true;
        miniVideoPlayer.muted = true;
        miniVideoPlayer.play().catch(e => console.error('小窗口视频播放失败:', e));

        // 显示小窗口，隐藏全屏
        miniVideo.style.display = 'block';
        videoOverlay.style.display = 'none';

        // 更新状态
        isVideoPlaying = true;
    }

    function expandVideo() {
        const videoOverlay = document.getElementById('videoOverlay');
        const videoPlayer = document.getElementById('videoPlayer');
        const miniVideo = document.getElementById('miniVideo');
        const miniVideoPlayer = document.getElementById('miniVideoPlayer');

        // 将小窗口视频源设置给全屏
        videoPlayer.src = miniVideoPlayer.src;
        videoPlayer.loop = true;
        videoPlayer.muted = true;
        videoPlayer.play().catch(e => console.error('全屏视频播放失败:', e));

        // 显示全屏，隐藏小窗口
        videoOverlay.style.display = 'block';
        miniVideo.style.display = 'none';

        // 更新状态
        isVideoPlaying = true;
    }

    // 切换视频类型 - 单视频元素优化版本
    function switchVideoType(videoType) {
        // 如果视频已经在播放，且类型相同，则不需要切换
        if (isVideoPlaying && currentVideoType === videoType) return;

        const videoOverlay = document.getElementById('videoOverlay');
        const videoPlayer = document.getElementById('videoPlayer');
        const miniVideo = document.getElementById('miniVideo');
        const miniVideoPlayer = document.getElementById('miniVideoPlayer');

        let videoSrc = '';

        if (videoType === 'speaking') {
            videoSrc = '/video/mv.mp4';
        } else if (videoType === 'idle') {
            videoSrc = '/video/mv1.mp4';
        }

        // 创建新的视频元素用于预加载
        const tempVideo = document.createElement('video');
        tempVideo.src = videoSrc;
        tempVideo.load();

        tempVideo.oncanplaythrough = () => {
            // 当视频可以播放时，立即切换
            if (videoOverlay.style.display === 'block') {
                // 全屏状态
                videoPlayer.src = videoSrc;
                videoPlayer.loop = true;
                videoPlayer.muted = true;
                videoPlayer.play().catch(e => console.error('视频切换失败:', e));
            } else if (miniVideo.style.display === 'block') {
                // 小窗口状态
                miniVideoPlayer.src = videoSrc;
                miniVideoPlayer.loop = true;
                miniVideoPlayer.muted = true;
                miniVideoPlayer.play().catch(e => console.error('小窗口视频切换失败:', e));
            } else {
                // 没有显示视频，显示全屏
                videoPlayer.src = videoSrc;
                videoPlayer.loop = true;
                videoPlayer.muted = true;
                videoPlayer.play().catch(e => console.error('视频播放失败:', e));
                videoOverlay.style.display = 'block';
            }

            currentVideoType = videoType;
            isVideoPlaying = true;

            // 预加载其他视频
            if (videoType === 'speaking') {
                preloadVideo('idle');
            } else {
                preloadVideo('speaking');
            }
        };

        // 设置超时，防止预加载失败
        setTimeout(() => {
            if (!isVideoPlaying || currentVideoType !== videoType) {
                // 如果预加载超时，仍然尝试切换
                if (videoOverlay.style.display === 'block') {
                    videoPlayer.src = videoSrc;
                    videoPlayer.loop = true;
                    videoPlayer.muted = true;
                    videoPlayer.play().catch(e => console.error('视频切换失败:', e));
                } else if (miniVideo.style.display === 'block') {
                    miniVideoPlayer.src = videoSrc;
                    miniVideoPlayer.loop = true;
                    miniVideoPlayer.muted = true;
                    miniVideoPlayer.play().catch(e => console.error('小窗口视频切换失败:', e));
                } else {
                    videoPlayer.src = videoSrc;
                    videoPlayer.loop = true;
                    videoPlayer.muted = true;
                    videoPlayer.play().catch(e => console.error('视频播放失败:', e));
                    videoOverlay.style.display = 'block';
                }

                currentVideoType = videoType;
                isVideoPlaying = true;
            }
        }, 500); // 500ms超时
    }

    /* ---------- 其他函数保持不变 ---------- */
    /* ---------- 输入模式切换 ---------- */
    function setInputMode(mode) {
        currentInputMode = mode;

        // 更新按钮状态
        document.querySelectorAll('.modeBtn').forEach(btn => {
            btn.classList.remove('active');
        });
        event.target.classList.add('active');

        // 显示/隐藏对应的输入区域
        if (mode === 'text') {
            document.getElementById('inputArea').style.display = 'flex';
            document.getElementById('voiceArea').style.display = 'none';
            document.getElementById('textInput').focus();
        } else {
            document.getElementById('inputArea').style.display = 'none';
            document.getElementById('voiceArea').style.display = 'flex';
        }
    }

    /* ---------- 文字输入处理 ---------- */
    function handleKeyPress(event) {
        if (event.key === 'Enter') {
            sendTextMessage();
        }
    }

    function sendTextMessage() {
        const textInput = document.getElementById('textInput');
        const message = textInput.value.trim();

        if (message) {
            addBubble('user', message);
            saveHistory('user', message);
            sendToBackend(message);
            textInput.value = ''; // 清空输入框
        } else {
            showStatus('请输入消息');
        }
    }

    /* ---------- 会话管理 ---------- */
    function generateSessionId() {
        const id = 'yufe_sess_' + Math.random().toString(36).substring(2, 10);
        localStorage.setItem('currentSessionId', id);
        return id;
    }

    function startNewSession() {
        currentSessionId = generateSessionId();
        document.getElementById('bubbleBox').innerHTML = '';
        document.getElementById('materialContent').innerHTML = '<div class="no-images">新会话已开始</div>';
        document.getElementById('sessionIndicator').style.display = 'inline-block';

        // 通知后端开始新会话（可选）
        fetch(`/api/user/chat/session/${currentSessionId}`, { method: 'DELETE' })
            .catch(e => console.log('清除会话失败（可能后端未实现）:', e));

        addBubble('assistant', '新会话已开始！我是云南财经大学信息学院智能校园助手，可以帮您查询校园信息、导航位置等。有什么可以帮您的？');
        updateSessionIndicator('新会话');

        // 显示待机动画
        switchVideoType('idle');

        // 聚焦到输入框
        document.getElementById('textInput').focus();
    }

    function updateSessionIndicator(status) {
        const indicator = document.getElementById('sessionIndicator');
        indicator.textContent = status;
        indicator.style.display = 'inline-block';
    }

    /* ---------- 语音↔文本 ---------- */
    const rec = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
    rec.lang = 'zh-CN'; rec.continuous = true; rec.interimResults = false;
    rec.onresult = e => {
        const txt = Array.from(e.results).slice(-1)[0][0].transcript;
        addBubble('user', txt);
        saveHistory('user', txt);
        sendToBackend(txt);
    };
    rec.onerror = e => showStatus('❌ 识别失败：' + e.error);
    rec.onend = () => {
        document.getElementById('recBtn').classList.remove('recording');
        showStatus('');
    };

    function startRec() {
        try {
            rec.start();
            document.getElementById('recBtn').classList.add('recording');
            showStatus('🎤 正在听...');
        } catch (e) {
            showStatus('❌ 语音识别启动失败');
        }
    }

    function stopRec() {
        rec.stop();
        document.getElementById('recBtn').classList.remove('recording');
        showStatus('');
    }

    /* ---------- 后端对话（增强版：支持记忆和图片） ---------- */
    async function sendToBackend(text) {
        try {
            // 更新会话指示器
            updateSessionIndicator('思考中...');

            document.getElementById('materialContent').innerHTML = '<div class="no-images">正在搜索相关信息...</div>';
            currentAssistantBubble = null;
            accumulatedText = '';

            // 构建请求数据，包含会话ID
            const requestData = {
                question: text,
                sessionId: currentSessionId
            };

            const response = await fetch('/api/user/chat/stream', {
                method: 'POST',
                headers: {'Content-Type': 'application/json'},
                body: JSON.stringify(requestData)
            });

            if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);

            const reader = response.body.getReader();
            const decoder = new TextDecoder('utf-8');
            currentAssistantBubble = createAssistantBubbleWithCursor();

            while (true) {
                const { done, value } = await reader.read();
                if (done) break;

                const chunk = decoder.decode(value, { stream: true });
                const lines = chunk.split('\n').filter(line => line.trim());

                for (const line of lines) {
                    try {
                        const message = JSON.parse(line);
                        handleStreamMessage(message);
                    } catch (e) {
                        console.error('解析消息失败:', e, '原始数据:', line);
                    }
                }
            }

            if (currentAssistantBubble) {
                const txtElement = currentAssistantBubble.querySelector('.txt');
                txtElement.innerHTML = accumulatedText;
            }

            saveHistory('assistant', accumulatedText);
            xfSpeak(accumulatedText); // 使用讯飞TTS替换原有语音合成
            updateSessionIndicator('会话中');

        } catch (e) {
            console.error('请求失败:', e);
            addBubble('assistant', '网络错误（请您先确认是否已经登录）：' + e.message);
            updateSessionIndicator('错误');
        }
    }

    /* ---------- 处理流式消息（增强记忆功能） ---------- */
    function handleStreamMessage(message) {
        switch (message.type) {
            case 'TEXT_CHUNK':
                if (message.content && currentAssistantBubble) {
                    accumulatedText += message.content;
                    const txtElement = currentAssistantBubble.querySelector('.txt');
                    txtElement.innerHTML = accumulatedText + '<span class="typing-cursor"></span>';
                    scrollToBottom();
                }
                break;

            case 'IMAGE_DATA':
                if (message.data && message.data.images) {
                    displayImages(message.data.images, message.data.searchQuery);
                }
                break;

            case 'INTENT_INFO':
                if (message.data) {
                    displayIntentInfo(message.data);
                    // 显示会话信息
                    if (message.data.sessionId) {
                        displaySessionInfo(message.data);
                    }
                }
                break;

            case 'SEARCH_RESULT':
                if (message.content) displaySearchSummary(message.content);
                break;

            case 'ERROR':
                console.error('服务器错误:', message.content);
                if (currentAssistantBubble) {
                    currentAssistantBubble.querySelector('.txt').textContent = '错误: ' + message.content;
                }
                break;

            case 'COMPLETE':
                // 显示完整的会话信息
                if (message.data && message.data.sessionId) {
                    displaySessionInfo(message.data);
                }
                break;
        }
    }

    /* ---------- 图片展示功能 ---------- */
    function displayImages(images, searchQuery) {
        const materialContent = document.getElementById('materialContent');
        if (!images || images.length === 0) {
            materialContent.innerHTML = '<div class="no-images">未找到相关图片信息</div>';
            return;
        }

        let html = '';
        if (searchQuery) html += `<div class="search-info">搜索关键词: "${searchQuery}"</div>`;
        html += `<div class="search-info">找到 ${images.length} 张相关图片</div>`;

        images.forEach((img, index) => {
            // 关键修复：正确处理图片URL
            let imageUrl = img.imagesUrl;

            // 处理本地文件路径：将本地路径转换为可访问的URL
            if (imageUrl.includes('src/main/resources/static/')) {
                // 提取static之后的部分
                const staticIndex = imageUrl.indexOf('static/');
                if (staticIndex !== -1) {
                    imageUrl = imageUrl.substring(staticIndex + 7); // 7是"static/"的长度
                }
            }

            // 确保URL以/开头
            if (!imageUrl.startsWith('/')) {
                imageUrl = '/' + imageUrl;
            }

            // 添加时间戳防止缓存
            imageUrl += (imageUrl.includes('?') ? '&' : '?') + 't=' + Date.now();

            html += `
                <div class="image-container">
                    <div class="image-title">${img.imagesName || '未命名图片'}</div>
                    <div class="image-description">${img.description || '暂无描述'}</div>
                    <img src="${imageUrl}" alt="${img.description}" class="image-preview"
                         onerror="handleImageError(this, '${img.imagesUrl}')"
                         onload="this.style.display='block'">
                    <div style="text-align:center;margin-top:8px;font-size:12px;color:#6c757d;">
                        图片 ${index + 1}/${images.length}
                    </div>
                </div>
            `;
        });

        materialContent.innerHTML = html;
        scrollToBottom();
    }

    /* ---------- 图片加载错误处理 ---------- */
    function handleImageError(imgElement, originalUrl) {
        console.warn('图片加载失败:', originalUrl);
        imgElement.style.display = 'none';

        // 尝试备用方案：直接使用原始URL
        if (originalUrl !== imgElement.src) {
            imgElement.src = originalUrl + '?t=' + Date.now();
            imgElement.style.display = 'block';
        } else {
            // 显示错误信息
            const container = imgElement.parentElement;
            const errorDiv = document.createElement('div');
            errorDiv.innerHTML = '<div style="color:#dc3545;text-align:center;font-size:12px;">图片加载失败</div>';
            container.appendChild(errorDiv);
        }
    }

    /* ---------- 意图信息展示 ---------- */
    function displayIntentInfo(intentData) {
        const materialContent = document.getElementById('materialContent');
        let existingContent = materialContent.innerHTML;
        if (existingContent.includes('no-images')) existingContent = '';

        const intentHtml = `
            <div class="search-info">
                <span class="intent-badge">意图识别</span>
                识别为: ${intentData.intent || '未知'}
                ${intentData.confidence ? `(置信度: ${(intentData.confidence * 100).toFixed(1)}%)` : ''}
            </div>
        `;
        materialContent.innerHTML = intentHtml + existingContent;
    }

    /* ---------- 会话信息展示 ---------- */
    function displaySessionInfo(sessionData) {
        const materialContent = document.getElementById('materialContent');
        let existingContent = materialContent.innerHTML;

        const sessionHtml = `
            <div class="session-info">
                <span class="intent-badge">会话信息</span>
                会话ID: ${sessionData.sessionId || currentSessionId}
                ${sessionData.historyTurns ? `| 对话轮次: ${sessionData.historyTurns}` : ''}
                ${sessionData.isNewSession ? '| 新会话' : '| 连续对话'}
            </div>
        `;
        materialContent.innerHTML = sessionHtml + existingContent;
    }

    /* ---------- 搜索摘要展示 ---------- */
    function displaySearchSummary(summary) {
        const materialContent = document.getElementById('materialContent');
        let existingContent = materialContent.innerHTML;
        const summaryHtml = `
            <div class="search-info">
                <span class="intent-badge">搜索完成</span>
                ${summary}
            </div>
        `;
        materialContent.innerHTML = summaryHtml + existingContent;
    }

    /* ---------- 创建带光标的助手气泡 ---------- */
    function createAssistantBubbleWithCursor() {
        const box = document.getElementById('bubbleBox');
        const div = document.createElement('div');
        div.className = 'bubble assistant';
        div.innerHTML = '<div class="txt"><span class="typing-cursor"></span></div>';
        box.appendChild(div);
        scrollToBottom();
        return div;
    }

    /* ---------- 气泡相关 ---------- */
    function addBubble(role, txt) {
        const box = document.getElementById('bubbleBox');
        const div = document.createElement('div');
        div.className = 'bubble ' + role;
        div.innerHTML = `<div class="txt">${txt}</div>`;
        box.appendChild(div);
        scrollToBottom();
    }

    function scrollToBottom() {
        const box = document.getElementById('bubbleBox');
        box.scrollTop = box.scrollHeight;
    }

    /* ---------- 讯飞TTS语音合成 ---------- */
    async function xfSpeak(text) {
        if (!text || text.trim() === '') return;

        try {
            // 关闭之前的连接
            if (xfTtsSocket) {
                xfTtsSocket.close();
            }

            // 初始化音频上下文
            if (!audioContext) {
                audioContext = new (window.AudioContext || window.webkitAudioContext)();
            }

            // 生成鉴权URL
            const authUrl = await generateAuthUrl();
            if (!authUrl) {
                throw new Error('鉴权失败');
            }

            // 建立WebSocket连接
            xfTtsSocket = new WebSocket(authUrl);

            xfTtsSocket.onopen = () => {
                console.log('讯飞TTS连接已建立');
                document.getElementById('stopBtn').disabled = false;
                document.getElementById('stopBtn').classList.add('reading');
                showStatus('🔊 正在合成语音...');

                // 显示说话动画
                switchVideoType('speaking');

                // 发送合成请求
                const requestData = {
                    common: {
                        app_id: XF_TTS_CONFIG.APPID
                    },
                    business: {
                        aue: "lame",        // 音频编码，lame表示mp3格式
                        sfl: 1,             // 开启流式返回
                        auf: "audio/L16;rate=16000", // 音频采样率
                        vcn: "x4_lingxiaolong", // 卡通龙音色
                        speed: 70,          // 语速 [0-100]
                        volume: 50,         // 音量 [0-100]
                        pitch: 10,          // 音高 [0-100]
                        bgs: 0,             // 背景音 0:无
                        tte: "UTF8",        // 文本编码
                        reg: "2",           // 英文发音方式
                        rdn: "0"            // 数字发音方式
                    },
                    data: {
                        status: 2,
                        text: btoa(unescape(encodeURIComponent(text))) // 修复：使用浏览器兼容的Base64编码
                    }
                };

                xfTtsSocket.send(JSON.stringify(requestData));
            };

            xfTtsSocket.onmessage = (event) => {
                const data = JSON.parse(event.data);

                if (data.code !== 0) {
                    console.error('讯飞TTS错误:', data);
                    showStatus('❌ 语音合成失败');
                    return;
                }

                if (data.data && data.data.audio) {
                    // 将base64音频数据添加到队列
                    const audioData = base64ToArrayBuffer(data.data.audio);
                    audioQueue.push(audioData);

                    // 如果没有正在播放，开始播放
                    if (!isPlaying) {
                        playAudioQueue();
                    }
                }

                if (data.data.status === 2) {
                    // 合成完成
                    console.log('讯飞TTS合成完成');
                    setTimeout(() => {
                        if (xfTtsSocket) {
                            xfTtsSocket.close();
                            xfTtsSocket = null;
                        }
                    }, 1000);
                }
            };

            xfTtsSocket.onerror = (error) => {
                console.error('讯飞TTS连接错误:', error);
                showStatus('❌ 语音合成连接错误');
                document.getElementById('stopBtn').disabled = true;
                document.getElementById('stopBtn').classList.remove('reading');
                // 如果出错，切换到待机动画
                switchVideoType('idle');
            };

            xfTtsSocket.onclose = () => {
                console.log('讯飞TTS连接已关闭');
            };

        } catch (error) {
            console.error('讯飞TTS初始化失败:', error);
            showStatus('❌ 语音合成失败');
            // 如果出错，切换到待机动画
            switchVideoType('idle');
        }
    }

    /* ---------- 讯飞TTS鉴权 ---------- */
    async function generateAuthUrl() {
        const { API_KEY, API_SECRET, HOST, PATH } = XF_TTS_CONFIG;

        // 生成RFC1123格式的时间戳
        const date = new Date().toUTCString();

        // 生成签名原文
        const signatureOrigin = `host: ${HOST}\ndate: ${date}\nGET ${PATH} HTTP/1.1`;

        // 使用HMAC-SHA256加密
        const signatureSha = await hmacSha256(signatureOrigin, API_SECRET);
        const signature = base64Encode(signatureSha);

        // 构建authorization
        const authorizationOrigin = `api_key="${API_KEY}", algorithm="hmac-sha256", headers="host date request-line", signature="${signature}"`;
        const authorization = base64Encode(authorizationOrigin);

        // 构建URL参数
        const urlParams = new URLSearchParams({
            host: HOST,
            date: date,
            authorization: authorization
        });

        return `wss://${HOST}${PATH}?${urlParams.toString()}`;
    }

    /* ---------- 加密工具函数 ---------- */
    async function hmacSha256(message, secret) {
        const encoder = new TextEncoder();
        const key = await crypto.subtle.importKey(
            'raw',
            encoder.encode(secret),
            { name: 'HMAC', hash: 'SHA-256' },
            false,
            ['sign']
        );

        const signature = await crypto.subtle.sign(
            'HMAC',
            key,
            encoder.encode(message)
        );

        return new Uint8Array(signature);
    }

    function base64Encode(arrayBuffer) {
        if (typeof arrayBuffer === 'string') {
            return btoa(arrayBuffer);
        }

        const bytes = new Uint8Array(arrayBuffer);
        let binary = '';
        for (let i = 0; i < bytes.byteLength; i++) {
            binary += String.fromCharCode(bytes[i]);
        }
        return btoa(binary);
    }

    function base64ToArrayBuffer(base64) {
        const binaryString = atob(base64);
        const bytes = new Uint8Array(binaryString.length);
        for (let i = 0; i < binaryString.length; i++) {
            bytes[i] = binaryString.charCodeAt(i);
        }
        return bytes.buffer;
    }

    /* ---------- 音频播放队列 ---------- */
    async function playAudioQueue() {
        if (isPlaying || audioQueue.length === 0) return;

        isPlaying = true;

        while (audioQueue.length > 0) {
            const audioData = audioQueue.shift();

            try {
                // 解码MP3数据
                const audioBuffer = await audioContext.decodeAudioData(audioData);
                const source = audioContext.createBufferSource();
                source.buffer = audioBuffer;
                source.connect(audioContext.destination);

                // 播放
                source.start();

                // 等待播放完成
                await new Promise(resolve => {
                    source.onended = resolve;
                });

            } catch (error) {
                console.error('音频播放错误:', error);
            }
        }

        isPlaying = false;
        document.getElementById('stopBtn').disabled = true;
        document.getElementById('stopBtn').classList.remove('reading');
        showStatus('');

        // 关键修改：语音播放完成后切换到待机动画
        switchVideoType('idle');
    }

    /* ---------- 停止语音合成 ---------- */
    function stopSpeak() {
        // 关闭WebSocket连接
        if (xfTtsSocket) {
            xfTtsSocket.close();
            xfTtsSocket = null;
        }

        // 清空音频队列
        audioQueue = [];
        isPlaying = false;

        document.getElementById('stopBtn').disabled = true;
        document.getElementById('stopBtn').classList.remove('reading');
        showStatus('对话已停止');

        // 切换到待机动画
        switchVideoType('idle');
    }

    /* ---------- 状态提示 ---------- */
    function showStatus(msg) {
        const statusEl = document.getElementById('status');
        if (msg) {
            statusEl.textContent = msg;
            statusEl.style.display = 'block';
            // 3秒后自动隐藏
            setTimeout(() => {
                statusEl.style.display = 'none';
            }, 3000);
        } else {
            statusEl.style.display = 'none';
        }
    }

    /* ---------- 历史记录管理 ---------- */
    // 初始化会话历史记录
    if (!localStorage.getItem('sessionHistory')) {
        localStorage.setItem('sessionHistory', JSON.stringify({}));
    }
    sessionHistory = JSON.parse(localStorage.getItem('sessionHistory'));

    function saveHistory(role, content) {
        if (content && content.trim().length > 0) {
            // 如果是用户消息，并且当前会话还没有记录，则保存为会话的第一条消息
            if (role === 'user' && !sessionHistory[currentSessionId]) {
                sessionHistory[currentSessionId] = {
                    firstMessage: content.substring(0, 20) + (content.length > 20 ? '...' : ''),
                    time: new Date().toLocaleString()
                };
                localStorage.setItem('sessionHistory', JSON.stringify(sessionHistory));
                renderHistory();
            }
        }
    }

    function renderHistory() {
        const list = document.getElementById('historyList');

        if (Object.keys(sessionHistory).length === 0) {
            list.innerHTML = '<div style="text-align:center;color:#6c757d;padding:20px;">暂无历史会话</div>';
            return;
        }

        let html = '';
        Object.keys(sessionHistory).reverse().forEach(sessionId => {
            const session = sessionHistory[sessionId];
            const isCurrentSession = sessionId === currentSessionId;
            const activeClass = isCurrentSession ? 'active' : '';

            html += `
                <div class="history-item ${activeClass}" onclick="loadSession('${sessionId}')">
                    <div class="title">${session.firstMessage}</div>
                    <div class="time">${session.time}</div>
                </div>
            `;
        });

        list.innerHTML = html;
    }

    function loadSession(sessionId) {
        // 切换到指定会话
        currentSessionId = sessionId;
        localStorage.setItem('currentSessionId', sessionId);

        // 清空当前对话
        document.getElementById('bubbleBox').innerHTML = '';
        document.getElementById('materialContent').innerHTML = '<div class="no-images">已切换到历史会话</div>';

        // 显示会话指示器
        updateSessionIndicator('历史会话');

        // 重新渲染历史记录
        renderHistory();

        // 显示待机动画
        switchVideoType('idle');

        // 聚焦到输入框
        document.getElementById('textInput').focus();
    }

    function toggleHistory() {
        document.getElementById('history').classList.toggle('collapsed');
    }

    /* ---------- 初始化 ---------- */
    document.addEventListener('DOMContentLoaded', function() {
        renderHistory();
        updateSessionIndicator('就绪');

        // 预加载初始视频
        preloadVideo('idle');

        // 聚焦到输入框
        document.getElementById('textInput').focus();

        setTimeout(() => {
            if (Object.keys(sessionHistory).length === 0) {
                addBubble('assistant', '您好！我是云南财经大学信息学院智能校园助手，基于先进AI技术为您提供校园信息服务。您可以询问关于校园导航、建筑位置、学校历史等各种问题。');
            }

            // 初始化时显示待机动画
            switchVideoType('idle');
        }, 500);
    });

    window.addEventListener('beforeunload', function() {
        if (currentStreamController) currentStreamController.abort();
        if (xfTtsSocket) xfTtsSocket.close();
    });
</script>
</body>
</html>
